package emulator.sidplay;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import emulator.analyzer.sid.SidImage;
import emulator.analyzer.sid.SidProcessor;
import emulator.assembler.SymbolTable;
import emulator.hardware.memory.MemoryBlock;
import emulator.util.ByteArrayWrapper;
import emulator.util.file.FileHelper;
import emulator.util.file.FileInfo;

public class SidPlayPrg {
	private int start_address;
	private byte [] prg_data;
	private int init_vector;
	private int exec_vector;
	private int zp_base;
	private int sid_base;
	private SidImage sid;
	private int song_addr;
	private int hwid_addr;
	private int title_addr;
	private int author_addr;
	private int year_addr;
	
	public SidPlayPrg()
	{
		start_address = 0;
		prg_data = null;
		init_vector = -1;
		exec_vector = -1;
		zp_base = -1;
		sid_base = -1;
		sid = null;
		song_addr = -1;
		hwid_addr = -1;
	}
	
	public void load(String prg_file_name, String label_file_name)
	{
		loadProgram(prg_file_name);
		loadSymbols(label_file_name);
	}

	private void loadSymbols(String label_file_name) {
		try {
			FileInputStream lbl_file = new FileInputStream(label_file_name);
			try
			{
				SymbolTable symbols = new SymbolTable();
				symbols.load(lbl_file, label_file_name);
				init_vector = symbols.findLabel("initadr");
				exec_vector = symbols.findLabel("execadr");
				zp_base = symbols.findLabel("zpuser");
				sid_base = symbols.findLabel("SIDIMAGE");
				song_addr = symbols.findLabel("song");
				hwid_addr = symbols.findLabel("hwid");
				title_addr = symbols.findLabel("title");
				author_addr = symbols.findLabel("author");
				year_addr = symbols.findLabel("copyright");
			}
			finally
			{
				try { lbl_file.close(); } catch (IOException e) { }
			}
		} catch (FileNotFoundException e) {
			init_vector = -1;
			exec_vector = -1;
		}
	}

	private void loadProgram(String prg_file_name) {
		FileInfo prg_info = FileHelper.getFileInfo(prg_file_name, FileHelper.FILE_FORMAT_PRG);
		start_address = prg_info.getStartAddress();
		prg_data = new byte [prg_info.getBlockSize()];
		prg_info.getLoadStrategy().loadToMemory(prg_file_name, new ByteArrayWrapper(prg_data), 0, prg_info.getBlockSize());
	}

	public void setSid(SidProcessor sid_processor) {
		sid = sid_processor.getSidAt(start_address+prg_data.length, zp_base, sid_base, hwid_addr);
	}

	public void write(String prg_file_name, int song) {
		FileInfo prg_info = FileHelper.getFileInfo(prg_file_name, FileHelper.FILE_FORMAT_PRG);
		MemoryBlock memory = new MemoryBlock(65536);
		for (int i = 0; i < prg_data.length; i++)
			memory.getData()[i+start_address] = prg_data[i];
		for (int i = 0; i < sid.getData().length; i++)
			memory.getData()[i+sid.getStartAddress()] = sid.getData()[i];
		
		putByte(memory, getSongAddr(), song);
		
		putWord(memory, init_vector, sid.getInitAddress());
		putWord(memory, exec_vector, sid.getExecAddress());
		
		putString(memory, title_addr, sid.getTitle(), 22);
		putString(memory, author_addr, sid.getAuthor(), 22);
		putString(memory, year_addr, sid.getYear(), 22);
		
		int end_address = sid.getStartAddress() + sid.getBlockSize();
		prg_info.getSaveStrategy().saveFromMemory(prg_file_name, memory, start_address, end_address - start_address);
	}

	private void putString(MemoryBlock memory, int address, String text, int len_max)
	{
		if (text != null)
		{
			String txpet = text.toUpperCase();
			int len = txpet.length();
			if (len > len_max)
				len = len_max;
			for (int i = 0; i < txpet.length(); i++)
			{
				memory.getData()[address+i] = (byte) txpet.charAt(i); 
			}
		}
	}

	private void putWord(MemoryBlock memory, int address, int word) {
		memory.getData()[address] = (byte) (word & 0xff);
		memory.getData()[address+1] = (byte) ((word >> 8) & 0xff);
	}

	private void putByte(MemoryBlock memory, int address, int byt) {
		memory.getData()[address] = (byte) (byt & 0xff);
	}
	
	public int getSongAddr() {
		return song_addr;
	}
}
